import Foundation
import UIKit
import Display
import MediaEditor

final class MarkerTool: DrawingElement {
    let uuid: UUID
    
    let drawingSize: CGSize
    let color: DrawingColor
    
    let renderLineWidth: CGFloat
    
    var translation = CGPoint()
    
    var points: [CGPoint] = []
    
    weak var metalView: DrawingMetalView?
    
    var isValid: Bool {
        return self.points.count > 6
    }
    
    var bounds: CGRect {
        var minX: CGFloat = .greatestFiniteMagnitude
        var minY: CGFloat = .greatestFiniteMagnitude
        var maxX: CGFloat = 0.0
        var maxY: CGFloat = 0.0
        
        for point in self.points {
            if point.x < minX {
                minX = point.x
            }
            if point.x > maxX {
                maxX = point.x
            }
            if point.y < minY {
                minY = point.y
            }
            if point.y > maxY {
                maxY = point.y
            }
        }
        
        return normalizeDrawingRect(CGRect(x: minX, y: minY, width: maxX - minX, height: maxY - minY).insetBy(dx: -80.0, dy: -80.0), drawingSize: self.drawingSize)
    }
        
    required init(drawingSize: CGSize, color: DrawingColor, lineWidth: CGFloat) {
        self.uuid = UUID()
        self.drawingSize = drawingSize
        self.color = color
        
        let minLineWidth = max(10.0, max(drawingSize.width, drawingSize.height) * 0.01)
        let maxLineWidth = max(20.0, max(drawingSize.width, drawingSize.height) * 0.09)
        let lineWidth = minLineWidth + (maxLineWidth - minLineWidth) * lineWidth
        
        self.renderLineWidth = lineWidth
    }
        
    func setupRenderView(screenSize: CGSize) -> DrawingRenderView? {
        return nil
    }
    
    func setupRenderLayer() -> DrawingRenderLayer? {
        return nil
    }
    
    private var didSetup = false
    func updatePath(_ point: DrawingPoint, state: DrawingGesturePipeline.DrawingGestureState, zoomScale: CGFloat) {
        let filterDistance: CGFloat = 10.0 / zoomScale
        if let lastPoint = self.points.last, lastPoint.distance(to: point.location) < filterDistance {
        } else {
            self.points.append(point.location)
        }
        
        self.didSetup = true
        self.metalView?.updated(point, state: state, brush: .marker, color: self.color, size: self.renderLineWidth)
    }
    
    func draw(in context: CGContext, size: CGSize) {
        guard !self.points.isEmpty else {
            return
        }
        context.saveGState()
        
        context.translateBy(x: self.translation.x, y: self.translation.y)
        
        self.metalView?.drawInContext(context)
        self.metalView?.clear()
        
        context.restoreGState()
    }
}

final class FillTool: DrawingElement {
    let uuid: UUID

    let drawingSize: CGSize
    let color: DrawingColor
    let isBlur: Bool
    var blurredImage: UIImage?
    
    var translation = CGPoint()
    
    var isValid: Bool {
        return true
    }
    
    var bounds: CGRect {
        return CGRect(origin: .zero, size: self.drawingSize)
    }
    
    required init(drawingSize: CGSize, color: DrawingColor, blur: Bool, blurredImage: UIImage?) {
        self.uuid = UUID()
        self.drawingSize = drawingSize
        self.color = color
        self.isBlur = blur
        self.blurredImage = blurredImage
    }

    func setupRenderView(screenSize: CGSize) -> DrawingRenderView? {
        return nil
    }
    
    func setupRenderLayer() -> DrawingRenderLayer? {
        return nil
    }
    
    func updatePath(_ path: DrawingPoint, state: DrawingGesturePipeline.DrawingGestureState, zoomScale: CGFloat) {
    }

    func draw(in context: CGContext, size: CGSize) {
        context.setShouldAntialias(false)

        context.setBlendMode(.copy)
        
        if self.isBlur {
            if let blurredImage = self.blurredImage?.cgImage {
                context.translateBy(x: size.width / 2.0, y: size.height / 2.0)
                context.scaleBy(x: 1.0, y: -1.0)
                context.translateBy(x: -size.width / 2.0, y: -size.height / 2.0)
                context.draw(blurredImage, in: CGRect(origin: .zero, size: size))
            }
        } else {
            context.setFillColor(self.color.toCGColor())
            context.fill(CGRect(origin: .zero, size: size))
        }
        
        context.setBlendMode(.normal)
    }
}
